﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using Citi.Helpers;
using Citi.ReportManager.Domain;
using System.Globalization;

namespace Citi.ReportManager.SchedulerUi
{
    public abstract class CopyFile
    {
        public abstract string StepDescription { set; }

        private string FilesPath
        {
            get
            {
                var filesPath = ConfigurationManager.AppSettings["FilesPath"];
                filesPath = ValidatePath(filesPath);

                if (!Directory.Exists(filesPath))
                    return FilesPathBackup;

                return filesPath;
            }
        }

        private string FilesPathBackup
        {
            get
            {
                var filesPath = ConfigurationManager.AppSettings["FilesPathBackup"];
                filesPath = ValidatePath(filesPath);

                return filesPath;
            }
        }

        private static string ValidatePath(string filesPath)
        {
            if (filesPath.ToUpper().Contains(Environment.MachineName.ToUpper()))
            {
                filesPath = filesPath.ToLower()
                    .Replace(string.Format(@"\\{0}.lac.nsroot.net\c$\", Environment.MachineName.ToLower()), @"C:\")
                    .Replace(string.Format(@"\\{0}\C$\", Environment.MachineName.ToLower()), @"C:\");
            }
            return filesPath;
        }

        private List<ReportFolder> ReportFolders { get; set; }
        private List<SupportedExtension> SupportedExtensions { get; set; }

        public void StartCopy(List<ReportFolder> reportFolders)
        {
            ReportFolders = reportFolders;
            StepDescription = "Loading supported extensions";
            SupportedExtensions = new SupportedExtension().SelectAll<SupportedExtension>();

            foreach (var reportFolder in ReportFolders)
            {
                StepDescription = string.Format("Category: '{0}'. Options: Move permanently: {1}. Days to backup: {2}. Include Directories: {3}.",
                    reportFolder.Category.Name, reportFolder.MoveFilePermanently, reportFolder.DaysToBackup, reportFolder.IncludeDirectories);
                var directoryToSave = Path.Combine(FilesPath, reportFolder.Id.ToString());

                StepDescription = string.Format("Reading Directory: '{0}'", reportFolder.FolderPath);
                if (!Directory.Exists(directoryToSave)) Directory.CreateDirectory(directoryToSave);
                if (!Directory.Exists(reportFolder.FolderPath)) continue;

                MoveFiles(reportFolder.FolderPath, directoryToSave, reportFolder);

                if (reportFolder.IncludeDirectories)
                    CopyDirectories(reportFolder.FolderPath, directoryToSave, reportFolder);
            }
        }

        public static IEnumerable<string> GetFiles(string path, string searchPattern, SearchOption searchOption)
        {
            string[] searchPatterns = searchPattern.Split('|');
            List<string> files = new List<string>();

            foreach (string sp in searchPatterns)
                files.AddRange(System.IO.Directory.GetFiles(path, sp, searchOption));

            files.Sort();
            return files.ToArray();
        }

        private void CopyDirectories(string directoryPath, string pathToSave, ReportFolder reportFolder)
        {
            var directories = Directory.GetDirectories(directoryPath).Where(x => !ReportFolders.Select(y => y.FolderPath.ToUpper()).Contains(x.ToUpper()));

            foreach (var directory in directories)
            {
                var directoryToSave = Path.Combine(pathToSave, Path.GetFileName(directory));

                StepDescription = string.Format("Reading Directory: '{0}'", directory);

                MoveFiles(directory, directoryToSave, reportFolder);

                if (Directory.GetDirectories(directory).Any())
                    CopyDirectories(directory, directoryToSave, reportFolder);
            }
        }

        private void MoveFiles(string directoryPath, string pathToSave, ReportFolder reportFolder)
        {
            var files = GetFiles(directoryPath, reportFolder.SearchPattern, SearchOption.TopDirectoryOnly)
                .Where(x => SupportedExtensions.Any(y => y.Extension == Path.GetExtension(x).Substring(1)))
                .ToList();

            if (files.Any())
                if (!Directory.Exists(pathToSave)) Directory.CreateDirectory(pathToSave);

            files.ForEach(file =>
            {
                var newFile = ConvertToXlsb(reportFolder, file);
                var fileFound = false;

                if (Path.GetExtension(newFile).ToLower() != ".zip")
                {
                    var zipFile = Path.Combine(pathToSave, string.Concat(Path.GetFileName(newFile), ".zip"));
                    fileFound = File.Exists(zipFile);

                    if (fileFound)
                        File.Delete(zipFile);

                    FileHelper.CompressFile(newFile, zipFile);

                    if (!fileFound)
                        SaveReport(reportFolder, file, zipFile);
                }
                else
                {
                    var zipFile = Path.Combine(pathToSave, Path.GetFileName(newFile));
                    fileFound = File.Exists(zipFile);
                    File.Copy(newFile, zipFile, true);

                    if (!fileFound)
                        SaveReport(reportFolder, file, zipFile);
                }

                if (reportFolder.MoveFilePermanently && File.GetLastWriteTime(file) < DateTime.Today.AddDays(-reportFolder.DaysToBackup))
                {
                    File.Delete(newFile);
                    File.Delete(file);
                }
            });
        }

        private string ConvertToXlsb(ReportFolder reportFolder, string file)
        {
            if (reportFolder.CanConvertToXlsb && (Path.GetExtension(file).ToLower() == ".xlsx" || Path.GetExtension(file).ToLower() == ".xls"))
            {
                try
                {
                    var convertedFile = Path.Combine(@"c:\temp", string.Concat(Path.GetFileNameWithoutExtension(file), ".xlsb"));

                    if (File.Exists(convertedFile)) File.Delete(convertedFile);

                    ExcelHelper.ConvertXlsToXlsb(file, convertedFile);

                    return convertedFile;
                }
                catch
                {
                    return file;
                }
            }

            return file;
        }

        private void SaveReport(ReportFolder reportFolder, string file, string fileToSave)
        {
            var report = new Report
            {
                ReportFolderId = reportFolder.Id,
                FileDate = GetFileDate(reportFolder, file),
                InsertDate = DateTime.Now,
                ReportName = fileToSave.Replace(string.Format(@"{0}\{1}\", FilesPath, reportFolder.Id), string.Empty),
                ExtensionId = SupportedExtensions.First(x => x.Extension == Path.GetExtension(file).Substring(1)).Id
            };
            report.Save(report);
        }

        private static DateTime GetFileDate(ReportFolder reportFolder, string file)
        {
            if (reportFolder.FileDateFormat == null)
                return File.GetLastWriteTime(file);

            var fileName = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(file));
            string date;

            if (reportFolder.FileDateFormatSeparator == null)
                date = file;
            else
            {
                var fileNameSplited = fileName.Split(new[] { reportFolder.FileDateFormatSeparator }, 10, StringSplitOptions.RemoveEmptyEntries).ToList();
                fileNameSplited.RemoveAt(0);

                date = string.Join(string.Empty, fileNameSplited);
            }

            int index = 0;
            DateTime dateConverted;
            var cultureInfo = new CultureInfo("pt-BR");

            while (index <= date.Count() + reportFolder.FileDateFormat.Count())
            {
                if (DateTime.TryParseExact(date.Substring(index, reportFolder.FileDateFormat.Count()), reportFolder.FileDateFormat,
                    cultureInfo, DateTimeStyles.None, out dateConverted))
                    return dateConverted;

                index++;
            }

            return File.GetLastWriteTime(file);
        }
    }
}
